package MuleBackend;

import java.awt.Color;
import java.util.ArrayList;

import javax.swing.ButtonModel;
import javax.swing.ImageIcon;

/**
* This class contains methods and variables necessary for initializing
* and instantiating a Player object. Players contain many important pieces of 
* information, such as a player's name, race, and color. It will also hold functions 
* pertaining to his or her inventory.
*/



public class Player {
	int playerID;
	private String name;
	ImageIcon race;
	Color color;
	int rank;
	private Inventory inventory;
	private ArrayList<Land> landsOwned;

	int x;
	int y;
	
	/**
	 * 
	 * @param name the player's name
	 * @param race the player's race
	 * @param color the player's color
	 * @param inventory the player's inventory
	 * @param landsOwned a list of the player's currently owned lands
	 */
	
	public Player(String name, ImageIcon race, Color color, int id){
		this.name = name;
		this.race = race;
		this.color = color;
		playerID = id;
		inventory = new Inventory();
		landsOwned = new ArrayList<Land>();
	}
	
	/**
	 * return the player character
	 */
	public ImageIcon getRace(){
		return race;
	}

	public int ownedLand(){
		return landsOwned.size();
	}
	
	public ImageIcon getMuleImage() { 
		int mule = inventory.getMule();
		if (mule == 1)return new ImageIcon("src/ShittyPackage/player'sMule.png");
		if (mule == 2)return new ImageIcon("src/ShittyPackage/foodMule.png");
		if (mule == 3)return new ImageIcon("src/ShittyPackage/energyMule.png");
		if (mule == 4)return new ImageIcon("src/ShittyPackage/smithoreMule.png");
		if (mule == 5)return new ImageIcon("src/ShittyPackage/crystiteMule.png");
		if (mule == 6)return new ImageIcon("src/ShittyPackage/assayImage.png");
		if (mule == 7)return new ImageIcon("src/ShittyPackage/landSaleImage.png");
		return null;
	}
	
	/**
	 * adds a land to the player's owned lands list
	 * @param land the land to be added to the player
	 */
	public void addLand(Land land) { this.landsOwned.add(land); }

	/**
	 * removes a land from the player's owned lands list
	 * @param land the lands to be removed from the player
	 */
	public void removeLand(Land land) {this.landsOwned.remove(land);}
	
	/**
	 * returns a string representation of the player
	 */
	public String toString(){
		return "Player Name :" + name + "\n" +
				"Player ID :" + playerID + "\n" +
				"Player color :" + color + "\n";
	}
	
	/**
	 * returns a list of the lands that the player owns
	 * @return an arraylist of the lands a player owns
	 */
	public ArrayList<Land> getLands() { return landsOwned; }
	
	/**
	 * getter method to get the color of the player
	 * @return the color of the player
	 */
	public Color getColor() { return this.color; }
	
	/**
	 * setter method to set the player number
	 * @param num the number of the player
	 */
	public void setPlayerID(int num) { this.playerID = num; }
	
	/**
	 * getter method to get the player number
	 * @return the number of the player
	 */
	public int getPlayerID() { return playerID; }
	
	/**
	 * setter method to set the lands that the player owns
	 * @param lands an arraylist of lands to give to the player
	 */
	public void setLands(ArrayList<Land> lands) { this.landsOwned = lands; }
	
	/**
	 * setter method to increment the crystite reserves of a player
	 * @param increment The amount of crystite to add to the player's inventory reserve.
	 * * A negative value passed means the player's reserves will be deducted by that amount.
	   A positive value passed means the player's reserves will be incremented by that amount.
	 */
	public void addCrystite(int increment) {
		inventory.crystite += increment;
		Inventory.totalCrystite+=increment;
	}
	/**
	 * setter method to increment the food reserves of a player
	 * @param increment The amount of food to add to the player's inventory reserve.
	 * * A negative value passed means the player's reserves will be deducted by that amount.
	   A positive value passed means the player's reserves will be incremented by that amount.
	 */
	public void addFood(int increment) {
		inventory.food += increment;
		Inventory.totalFood+=increment;
	}
	/**
	 * setter method to increment the energy reserves of a player
	 * @param increment The amount of energy to add to the player's inventory reserve.
	 * * A negative value passed means the player's reserves will be deducted by that amount.
	   A positive value passed means the player's reserves will be incremented by that amount.
	 */
	public void addEnergy(int increment) {
		inventory.energy += increment;
		Inventory.totalEnergy+=increment;
	}
	/**
	 * setter method to increment the smithore reserves of a player
	 * @param increment The amount of smithore to add to the player's inventory reserve. 
	 * A negative value passed means the player's reserves will be deducted by that amount.
	   A positive value passed means the player's reserves will be incremented by that amount.
	 */
	public void addSmithore(int increment) {
		inventory.smithore += increment;
		Inventory.totalSmithore+=increment;
	}
	/**
	 * method that adds money to the player's inventory
	 * @param amount the amount of money to be added
	 */
	public void addMoney(int amount) { 
		inventory.addMoney(amount);
		Inventory.totalMoney+=amount;
	}	
	/**
	 * method that removes money from the player's inventory
	 * @param amount the amount of money to be removed
	 */
	public void deductMoney(int amount) { inventory.deductMoney(amount); }
	
	/**
	 * getter method to return the amount of money in the players inventory
	 * @return
	 */
	public int getMoney() { return inventory.money; }
	/**
	 * 
	 * @return amount of food
	 */
	public int getFood() { return inventory.getFood(); }
	/**
	 * 
	 * @return player's amount of energy
	 */
	public int getEnergy() { return inventory.energy; }
	/**
	 * 
	 * @return player Mule
	 */
	public int getMule() { return inventory.getMule(); }
	/**
	 * @return player's smithore reserves
	 */
	public int getSmithore() { return inventory.smithore; }
	/**
	 * 
	 * @return player amount of crystite
	 */
	public int getCrystite() { return inventory.crystite; }
	
	/**
	 * 
	 * @param mule sets the type of mule, or whether the player has a mule
	 */
	public void setMule(int mule) { inventory.setMule(mule); }
	/**
	 * @return deducts amount of food player has.
	 */
	public void deductFood(int food) { inventory.deductFood(food); }
	
	
	/**
	 * hasMoney checks if player has sufficient money
	 * @return true if he does, false if he doesn't
	 */
	public boolean hasMoney(int amount){
		if(getInventory().getMoney()>=amount) { 
			return true;
		} else {
			return false; 
		}
	}
	
	/**
	 * getter method to get the name of the player
	 * @return the name of the player
	 */
	public String getName() { return name; }
	
	/**
	 * getTurnTime calculates the amount of time a player is given in turns
	 * @param round the current round
	 * @return returns the time allotted to player
	 */
	public int getTurnTime(int round){
		int foodReq = ((round-1)/4)+3;
		int curFood = getInventory().getFood();
		/* Print statements */
		System.out.println("Player ID :" + this.playerID + " Food before :" + curFood);
		if(curFood==0){
			getInventory().deductFood(0);
			return 10;
		}
		if(curFood<foodReq){
			getInventory().deductFood(curFood);
			return 15;
		}
		getInventory().deductFood(foodReq);
		return 20;
	}
	
	public int getMediumTurnTime(int round){
		int foodReq = ((round-1)/4)+4;
		int curFood = getInventory().getFood();
		/* Print statements */
		System.out.println("Player ID :" + this.playerID + " Food before :" + curFood);
		if(curFood==0){
			getInventory().deductFood(0);
			return 10;
		}
		if(curFood<foodReq){
			getInventory().deductFood(curFood);
			return 15;
		}
		getInventory().deductFood(foodReq);
		return 20;
	}
	
	public int getDifficultTurnTime(int round){
		int foodReq = (((2*round)-1)/4)+4;
		int curFood = getInventory().getFood();
		/* Print statements */
		System.out.println("Player ID :" + this.playerID + " Food before :" + curFood);
		if(curFood==0){
			getInventory().deductFood(0);
			return 10;
		}
		if(curFood<foodReq){
			getInventory().deductFood(curFood);
			return 15;
		}
		getInventory().deductFood(foodReq);
		return 20;
	}
	
	/**
	 * calcLandMoney calculates the net worth of the lands the player owns
	 * @return land monetary value
	 */
	public int calcLandMoney() { return landsOwned.size()*200; }
	
	/**
	 * sortPlayers arranges players from poorest to richest
	 * @param players list of players
	 */
	public static void sortPlayers(ArrayList<Player> players){
		//calculates the net worth of players so that we can sort them
		int[] netWorth = new int[players.size()];
		for(int k=0;k<players.size();k++){
			netWorth[k]=players.get(k).calcLandMoney() + players.get(k).getMoney();
		}
		
		/* Printing Statements */
		System.out.println("Order before sorting");
		for(int k=0;k<players.size();k++){
			System.out.println("Score = " + netWorth[k] + " Player ID" + players.get(k).playerID);
		}
		
			//Standard insertion sort
			int j;
	        for (int i = 1; i < players.size(); i++) {
	        	int temp = netWorth[i];
	        	Player tempPlayer = players.get(i);
	        	j = i;
	            while (j > 0 && temp < netWorth[j - 1]) {
	            	//System.out.println("PLAYER SWAP HAPPENED");
	                netWorth[j] = netWorth[j-1];
	                players.set(j, players.get(j-1));
	                j--;
	            }
	            netWorth[j] = temp;
	            players.set(j, tempPlayer);
	        }
	        
	        System.out.println("Order after sorting");
			for(int k=0;k<players.size();k++){
				System.out.println("Score = " + netWorth[k] + " Player ID" + players.get(k).playerID);
			}
	        
	}
	/**
	 * Returns the position of the player in the array depending on his ID
	 * @param players list of players
	 * @param ID the player's ID
	 * @return index of player
	 */
	public static int returnIndexByID(ArrayList<Player> players, int ID){
		for(int k=0;k<players.size();k++)
			if(players.get(k).playerID == ID)
				return k;
		return -1;
	}
	/**
	 * Returns the ID of player depending on his position
	 * @param players list of players
	 * @param index the index of player in the list
	 * @return ID of player
	 */
	public static int returnIDByIndex(ArrayList<Player> players, int index){
		return players.get(index).playerID;
	}

	/**
	 * getter method to get the player's inventory
	 * @return the inventory of the player
	 */
	public Inventory getInventory() { return inventory; }

	/**
	 * setter method to set the players inventory to an inventory
	 * @param inventory the inventory to give to the player
	 */
	public void setInventory(Inventory inventory) { this.inventory = inventory; }
	
	/**
	 * returns the amount of goods the player has for the corresponding good type
	 * @param goodType
	 * @return
	 */
	public int unitsToSell(int goodType) {
		if(goodType==0) return getFood()-1;
		if(goodType==1) return getEnergy()-1;
		if(goodType==2) return getSmithore()-1;
		if(goodType==3) return getCrystite()-1;
		return 0;
	}
	/**
	 * adds goods to the Player according to the good Type
	 * @param goodType
	 */
	public void addGood(int goodType) {
		if(goodType==0) inventory.addFood(1);
		if(goodType==1) inventory.addEnergy(1);
		if(goodType==2) inventory.addSmithore(1);
		if(goodType==3) inventory.addCrystite(1);
		
	}
	/**
	 * subtracts goods from the Player according to the good Type
	 * @param goodType
	 */
	public void deductGood(int goodType) {
		if(goodType==0) inventory.addFood(-1);
		if(goodType==1) inventory.addEnergy(-1);
		if(goodType==2) inventory.addSmithore(-1);
		if(goodType==3) inventory.addCrystite(-1);
		
	}
	
} //end of player class